import Codemirror from '../../assets/js/codemirror'
import '../../assets/js/codemirror/mode/xml'
import '../../assets/js/codemirror/mode/css'
import '../../assets/js/codemirror/mode/javascript'
import '../../assets/js/codemirror/mode/markdown'
import codemirrorConfig from '../../assets/js/codemirror/config'
import '../../assets/js/codemirror/styles/codemirror.css'
import common from '../../mixins/common'
import marked from '../../config/marked'

export default {
  name: 'markdown-pro',
  mixins: [common],
  data () {
    return {
      pro: true,
      editor: null, // 编辑器实例
      lastPos: '' // 光标最后所在位置
    }
  },

  mounted () {
    this.init()
    this.createEditor()
  },
  methods: {
    init () { // 初始化
      this.currentValue = this.value
      this.themeName = this.theme
      this.preview = this.isPreview
      this.currentValue = this.value
      if (this.isPreview) {
        return
      }
      setTimeout(() => {
        if (this.autoSave) {
          this.timerId = setInterval(() => {
            this.handleSave()
          }, this.interval)
        }
      }, 20)
    },
    createEditor () { // 初始化左侧编辑器
      this.editor = new Codemirror(this.$refs.codemirror, {
        value: this.currentValue,
        onload: (data) => {
          const { doc: { height = 0 } } = data
          this.editorScrollHeight = height
        },
        ...codemirrorConfig
      })

      this.addEditorLintener()
      this.$emit('on-ready', {
        vm: this,
        insertContent: this.insertContent
      })
    },
    addEditorLintener () { // 绑定监听事件
      const editor = this.editor
      editor.on('change', data => {
        this.lastPos = editor.getCursor()
        this.currentValue = editor.getValue()
        const {
          doc: { height }
        } = data
        this.editorScrollHeight = height
      })
      editor.on('scroll', this.markdownScroll)
      editor.on('paste', this.handlePaste)
      editor.on('keydown', (data, e) => {
        if (e.keyCode === 83) {
          if (e.metaKey || e.ctrlKey) {
            e.preventDefault()
            this.handleSave()
          }
        } else if (e.keyCode === 13) {
          this.listerenKeyupEnter(e)
        } else if (e.keyCode === 8) {
          this.listerenDelete(data)
        }
      })
      editor.on('focus', () => {
        this.lastPos = editor.getCursor()
      })
    },
    insertContent (str) { // 插入文本
      this.editor.replaceSelection(str)
      this.lastInsert = str.replace(/\n/g, '')
    },
    setCursor (line = 0, ch = 0) { // 设置焦点
      const { editor } = this
      editor.setCursor(line, ch)
      editor.focus()
    },

    insertStrong () { // 粗体
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('**' + selection + '**')
      } else {
        this.insertContent('****')
        this.setCursor(line, ch + 2)
      }
    },
    insertItalic () { // 斜体
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('*' + selection + '*')
      } else {
        this.insertContent('**')
        this.setCursor(line, ch + 1)
      }
    },
    insertUnderline () { // 下划线
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('<u>' + selection + '</u>')
      } else {
        this.insertContent('<u></u>')
        this.setCursor(line, ch + 3)
      }
    },
    insertOverline () { // 删除线
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('~~' + selection + '~~')
      } else {
        this.insertContent('~~~~')
        this.setCursor(line, ch + 2)
      }
    },
    insertTitle (level) { // 插入标题
      const titles = {
        1: '#  ',
        2: '##  ',
        3: '###  ',
        4: '####  ',
        5: '#####  ',
        6: '######  '
      }
      const { editor, lastPos = {} } = this
      const { line } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n' + titles[level] + selection + '\n')
      } else {
        const title = titles[level]
        if (editor.isClean()) {
          this.insertContent(title)
          this.setCursor(0, title.length)
        } else {
          this.insertContent('\n' + title)
          this.setCursor(line + 1, title.length)
        }
      }
    },
    insertLine () { // 插入分割线
      const { editor } = this
      if (editor.isClean()) {
        this.insertContent('----\n')
      } else {
        this.insertContent('\n\n----\n')
      }
    },
    insertQuote () { // 引用
      const { editor, lastPos = {} } = this
      const { line = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n>  ' + selection + '\n\n')
      } else {
        if (editor.isClean()) {
          this.insertContent('>  ')
          this.setCursor(0, 3)
        } else {
          this.insertContent('\n>  ')
          this.setCursor(line + 1, 3)
        }
      }
    },
    insertUl () { // 无序列表
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n-  ' + selection + '\n\n')
      } else {
        if (editor.isClean() || ch === 0) {
          this.insertContent('-  ')
          this.setCursor(line, 3)
        } else {
          this.insertContent('\n-  ')
          this.setCursor(line + 1, 3)
        }
      }
    },
    insertOl () { // 有序列表
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n1.  ' + selection + '\n\n')
      } else {
        if (editor.isClean() || ch === 0) {
          this.insertContent('1.  ')
          this.setCursor(line, 4)
        } else {
          this.insertContent('\n1.  ')
          this.setCursor(line + 1, 4)
        }
      }
    },
    insertCode () { // 插入code
      const { editor, lastPos = {} } = this
      const { line } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n```\n' + selection + '\n```\n')
      } else {
        if (editor.isClean()) {
          this.insertContent('```\n\n```')
          this.setCursor(1, 0)
        } else {
          this.insertContent('\n```\n\n```')
          this.setCursor(line + 2, 0)
        }
      }
    },
    insertFinished () { // 已完成列表
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n- [x] ' + selection + '\n\n')
      } else {
        if (editor.isClean() || ch === 0) {
          this.insertContent('- [x] ')
          this.setCursor(line, 6)
        } else {
          this.insertContent('\n- [x] ')
          this.setCursor(line + 1, 6)
        }
      }
    },
    insertNotFinished () { // 未完成列表
      const { editor, lastPos = {} } = this
      const { line = 0, ch = 0 } = lastPos
      const selection = editor.getSelection()
      if (selection) {
        this.insertContent('\n- [ ] ' + selection + '\n\n')
      } else {
        if (editor.isClean() || ch === 0) {
          this.insertContent('- [ ] ')
          this.setCursor(line, 6)
        } else {
          this.insertContent('\n- [ ] ')
          this.setCursor(line + 1, 6)
        }
      }
    },
    listerenKeyupEnter (e) { // 回车事件
      const { lastInsert } = this
      if (lastInsert) {
        const list = ['-', '- [ ]', '- [x]']
        if (list.includes(lastInsert.trim())) {
          e.preventDefault()
          this.insertContent('\n' + lastInsert)
        } else if (/^\d+\.$/.test(lastInsert.trim())) {
          e.preventDefault()
          this.insertContent(
            '\n' + (parseInt(lastInsert, 0) + 1) + '.  '
          )
        }
      }
    },
    listerenDelete () { // 删除 backup
      setTimeout(() => {
        const { editor } = this
        if (!editor.isClean()) {
          const value = editor.getValue()
          if (value.split('\n').pop() === '') {
            this.lastInsert = ''
          }
        }
      }, 20)
    },
    onDelete () { // 删除时,以回车为界分割，如果数组最后一个元素为''时，将行一次插入的共嗯那个置为空，避免回车时再次插入
      const lines = this.currentValue.split('\n')
      if (lines[lines.length - 1] === '') {
        this.lastInsert = ''
      }
    },
    markdownScroll (data = {}) { // 编辑器区域滚动
      if (this.scrolling && this.scrollSide === 'left') {
        const {
          doc: { height, scrollTop }
        } = data
        const preview = this.$refs.preview
        const contentHeight = preview.offsetHeight
        const previewScrollHeight = preview.scrollHeight
        preview.scrollTop = parseInt(
          (scrollTop * (previewScrollHeight - contentHeight)) /
                    (height - contentHeight),
          0
        )
      }
    },
    previewScroll () { // 预览内容区域滚动
      if (this.scrolling && this.scrollSide === 'right') {
        const preview = this.$refs.preview
        const contentHeight = preview.offsetHeight
        const previewScrollHeight = preview.scrollHeight
        const previewScrollTop = preview.scrollTop
        const scrollTop = parseInt((previewScrollTop * (this.editorScrollHeight - contentHeight)) / (previewScrollHeight - contentHeight), 0)
        this.editor.scrollTo(0, scrollTop)
      }
    },
    redo () {
      const { editor } = this
      editor.redo()
      setTimeout(() => {
        editor.refresh()
      }, 20)
    }
  },
  watch: {
    currentValue () {
      clearTimeout(this.timeoutId)
      this.timeoutId = setTimeout(() => {
        const { currentValue } = this
        let html = marked(currentValue, {
          sanitize: false,
          ...this.markedOptions
        }).replace(/href="/gi, 'target="_blank" href="')
        if (this.copyCode && html !== '') {
          html = html.replace(/<pre>/g, '<div class="code-block"><span class="copy-code">' + this.copyBtnText + '</span><pre>').replace(/<\/pre>/g, '</pre></div>')
        }
        this.html = html
        this.addImageClickListener()
        this.addCopyListener()
        this.$emit('input', currentValue)
      }, 30)
    },
    value () {
      const { value, currentValue } = this
      if (currentValue !== value) { // 由于用户输入而造成的value变化，不对editor设置值
        this.currentValue = value
        this.editor.setOption('value', value)
      }
    }
  }
}
